package com.ccl.iot.device;import java.lang.ref.WeakReference;
import java.util.Timer;
import java.util.TimerTask;

import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.FontMetrics;
import android.graphics.Rect;

public class Marquee {
	/*
	 * 	Static functions
	 */
	private static int KMARQUEE_START_INTERVAL = 1000;
	private static int KMARQUEE_REFRESH_INTERVAL = 40;	//25 frames
	private static float KMARQUEE_STEP_WIDTH = 1;
	
	private static Timer gTimer = null;
	private static volatile int gTaskCount = 0;
	
	private static void StopTimer(){
		if (gTimer != null){
			if (gTaskCount == 0){
				gTimer.cancel();
				gTimer = null;
			}
		}
	}
	
	/*
	 * 	Interfaces
	 */
	public interface OnUpdateListener{
		public void onUpdate();
	}
	
	/*
	 * 	Non-static functions
	 */
	private WeakReference<OnUpdateListener> iUpdateListener = null;
	
	private String iText;
	private String iCacheText;
	
	private Paint iPaint;
	private float iTextHeight;
	private float iTextBaseLine;
	private Rect iTextBounds = new Rect();
	private boolean iIsLongText = false;
	private boolean iDrawRtoL = false;
	private float iDrawLeft = 0;

	private int iWidth;
	private int iHeight;
	
	private volatile boolean iRolling = false;
	
	Marquee(){
		iPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		
		updateTextInfo();
	}
	
	public void setUpdateListener(OnUpdateListener aListener){
		if (aListener != null){
			if (iUpdateListener == null){
				iUpdateListener = new WeakReference<OnUpdateListener>(aListener);
			}else{
				if (iUpdateListener.get() != aListener){
					iUpdateListener = new WeakReference<OnUpdateListener>(aListener);
				}else{
					return;
				}
			}
			
			updateText();
		}else{
			iUpdateListener = null;
		}
	}
	
	private void updateTextInfo(){
		if (iPaint != null){
			FontMetrics tFontMetrics;
			
			tFontMetrics = iPaint.getFontMetrics();
			iTextHeight = (float) Math.ceil(tFontMetrics.descent - tFontMetrics.ascent);
			iTextBaseLine = (iTextHeight - tFontMetrics.bottom + tFontMetrics.top) / 2 - tFontMetrics.top;
		}
	}
	
	private void updateText(){
		if (iText != null){
			int tTextWidth;
			
			iPaint.getTextBounds(iText, 0, iText.length(), iTextBounds);
			tTextWidth = iTextBounds.width();
			
			if (iWidth > 0){
				if (tTextWidth > iWidth){
					iIsLongText = (tTextWidth - iWidth) > (iWidth >> 1);
					
					if (iIsLongText){
						iCacheText = iText + "    " + iText;
						
						iPaint.getTextBounds(iCacheText, 0, iCacheText.length(), iTextBounds);
						
						iTextBounds.right -= tTextWidth;
					}else{
						iDrawRtoL = true;
						iCacheText = iText;
					}
					
					iDrawLeft = 0;
					
					startMarquee();
				}else{
					iCacheText = iText;
					
					iDrawLeft = (iWidth - iTextBounds.width()) >> 1;
				}
			}else{
				iCacheText = null;
			}
		}else{
			iCacheText = null;
		}
		onUpdate();
	}
	
	public boolean setText(String aText){
		boolean tRet = false;
		if (aText != null){
			if (iText == null || aText.equals(iText) == false){
				iText = new String(aText);
				
				tRet = true;
			}
		}else if (iText != null){
			iText = null;
			
			tRet = true;
		}
		
		if (tRet){
			updateText();
		}
		
		return tRet;
	}
	
	public float getTextSize(){
		if (iPaint != null){
			return iPaint.getTextSize();
		}
		
		return 12;
	}
	
	public void setTextSize(float aTextSize){
		if (iPaint != null && iPaint.getTextSize() != aTextSize){
			iPaint.setTextSize(aTextSize);
			
			updateTextInfo();
			updateText();
		}
	}
	
	public void setTextColor(int aColor){
		if (iPaint != null && iPaint.getColor() != aColor){
			iPaint.setColor(aColor);
			
			onUpdate();
		}
	}
	
	public boolean setSize(int aWidth, int aHeight){
		
		if (iWidth != aWidth || iHeight != aHeight){
			iWidth = aWidth;
			iHeight = aHeight;
			
			updateText();
			
			return true;
		}
		
		return false;
	}
	
	public float getFontHeight(){
		return iTextHeight;
	}
	
	private void marqueeTask(){
		boolean tStart = false;
		
		if (iIsLongText){
			if (iDrawLeft > -iTextBounds.width()){
				iDrawLeft -= KMARQUEE_STEP_WIDTH;
			}else{
				tStart = true;
				
				iDrawLeft = 0;
			}
		}else{
			if (iDrawRtoL){
				if (iDrawLeft >= -(iTextBounds.width() - iWidth)){
					iDrawLeft -= KMARQUEE_STEP_WIDTH;
				}else{
					tStart = true;
					
					iDrawRtoL = false;
				}
			}else{
				if (iDrawLeft <= 0){
					iDrawLeft += KMARQUEE_STEP_WIDTH;
				}else{
					tStart = true;
					
					iDrawRtoL = true;
				}
			}
		}
		
		if (onUpdate()){
			startMarqueeTask(tStart ? KMARQUEE_START_INTERVAL : KMARQUEE_REFRESH_INTERVAL);
		}else{
			StopTimer();
		}
	}
		
	private void startMarqueeTask(long aDelay){
		if (iRolling == false){
			iRolling = true;
			
			if (gTimer == null){
				gTimer = new Timer("Marquee update thread");
			}
			
			gTaskCount++;
			
			gTimer.schedule(new TimerTask(){
				@Override
				public void run() {
					gTaskCount--;
					
					iRolling = false;
					
					marqueeTask();
				}
			}, aDelay);
		}
	}
	
	private void startMarquee(){
		startMarqueeTask(KMARQUEE_START_INTERVAL);
	}
	
	private boolean onUpdate(){
		if (iUpdateListener != null){
			OnUpdateListener tListener = iUpdateListener.get();
			
			if (tListener != null){
				tListener.onUpdate();
				
				return true;
			}
		}
		
		return false;
	}
	
	public boolean drawToCanvas(Canvas aCanvas, float aLeft, float aTop){
		if (aCanvas != null && iCacheText != null && iWidth > 0){
			boolean tSaved = false;
			
			if (iTextBounds.width() > iWidth){
				tSaved = true;
				aCanvas.save();
				aCanvas.clipRect(aLeft, aTop, aLeft + iWidth, aTop + iHeight);
			}
			
			aCanvas.drawText(iCacheText, aLeft + iDrawLeft, aTop + iTextBaseLine, iPaint);
			
			if (tSaved){
				aCanvas.restore();
			}
		}
		
		return false;
	}
	
}
